using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Rotempco.Core.ORM.Objects.Stores
{
    public class SingletonStore
    {
        #region [ Singleton ]

        static readonly SingletonStore _Instance = new SingletonStore();

        static SingletonStore()
        {
        }

        private SingletonStore()
        {
            InstanceDictionary = new Dictionary<string, object>();
            ThreadInstanceDictionary = new Dictionary<int, Dictionary<string, object>>();
        }

        public static SingletonStore Instance
        {
            get
            {
                return _Instance;
            }
        }

        #endregion

        private static object LockVariable = true;

        public bool SingletonByThread { get; set; }
        private Dictionary<string, object> InstanceDictionary;
        private Dictionary<int, Dictionary<string, object>> ThreadInstanceDictionary;

        public void ClearStores()
        {
            lock(LockVariable)
            {
                if (SingletonByThread)
                {
                    int currentThreadId = Thread.CurrentThread.ManagedThreadId;

                    if (ThreadInstanceDictionary.ContainsKey(currentThreadId))
                        ThreadInstanceDictionary.Remove(currentThreadId);
                }
                else
                    InstanceDictionary = new Dictionary<string, object>();
            }
        }

        public void SetCache(Dictionary<string, object> innerThreadInstanceDictionary)
        {
            lock(LockVariable)
            {
                int currentThreadId = Thread.CurrentThread.ManagedThreadId;

                if (ThreadInstanceDictionary.ContainsKey(currentThreadId))
                {
                    if (ThreadInstanceDictionary[currentThreadId] == innerThreadInstanceDictionary)
                        return;

                    ThreadInstanceDictionary.Remove(currentThreadId);
                }

                ThreadInstanceDictionary.Add(currentThreadId, innerThreadInstanceDictionary);
            }
        }

        public T GetInstance<T>(bool instanceByThread) where T : class, new()
        {
            lock(LockVariable)
            {
                string singletonName = typeof(T).FullName;
                if (SingletonByThread && instanceByThread)
                {
                    int currentThreadId = Thread.CurrentThread.ManagedThreadId;
                    if (!ThreadInstanceDictionary.ContainsKey(currentThreadId))
                        ThreadInstanceDictionary.Add(currentThreadId, new Dictionary<string, object>());

                    if (!ThreadInstanceDictionary[currentThreadId].ContainsKey(singletonName))
                        ThreadInstanceDictionary[currentThreadId].Add(singletonName, new T());

                    return (T)ThreadInstanceDictionary[currentThreadId][singletonName];
                }
                else
                {
                    if (!InstanceDictionary.ContainsKey(singletonName))
                        InstanceDictionary.Add(singletonName, new T());

                    return (T)InstanceDictionary[singletonName];
                }
            }
        }

        public void ClearStore<T>()
        {
            lock(LockVariable)
            {
                string singletonName = typeof(T).FullName;

                if (SingletonByThread)
                {
                    int currentThreadId = Thread.CurrentThread.ManagedThreadId;

                    if (ThreadInstanceDictionary.ContainsKey(currentThreadId))
                        if (ThreadInstanceDictionary[currentThreadId].ContainsKey(singletonName))
                            ThreadInstanceDictionary[currentThreadId].Remove(singletonName);
                }
                else
                {
                    if (InstanceDictionary.ContainsKey(singletonName))
                        InstanceDictionary.Remove(singletonName);
                }
            }
        }
    }
}
